package com.nineclock.system.service.impl;
import java.util.Date;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.system.dto.SysCompanyUserDTO;
import com.nineclock.system.dto.SysDepartmentDTO;
import com.nineclock.system.dto.SysRoleDTO;
import com.nineclock.system.excel.ExcelMember;
import com.nineclock.system.listener.ExcelMemberListener;
import com.nineclock.system.mapper.*;
import com.nineclock.system.pojo.*;
import com.nineclock.system.service.SysCompanyUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class SysCompanyUserServiceImpl implements SysCompanyUserService {
    @Autowired
    private SysCompanyUserMapper companyUserMapper;
    @Autowired
    private SysRoleMapper roleMapper;
    @Autowired
    private SysDepartmentMapper departmentMapper;
    @Autowired
    private SysUserMapper userMapper;
    @Autowired
    private SysCompanyUserRoleMapper companyUserRoleMapper;
    @Override
    public List<SysCompanyUserDTO> queryCompanyUser(Long userId, Long companyId) {
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getUserId,userId);
        if (companyId != null){
            wrapper.eq(SysCompanyUser::getCompanyId,companyId);
        }
        List<SysCompanyUser> sysCompanyUsers = companyUserMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(sysCompanyUsers)){
            throw new NcException(ResponseEnum.USER_NOT_JOIN_COMPANY);
        }
        List<SysCompanyUserDTO> sysCompanyUserDTOList = BeanHelper.copyWithCollection(sysCompanyUsers, SysCompanyUserDTO.class);
        for (SysCompanyUserDTO sysCompanyUserDTO : sysCompanyUserDTOList) {
            List<SysRole> sysRoles = roleMapper.queryRoleByCompanyUserId(sysCompanyUserDTO.getId());
            List<SysRoleDTO> sysRoleDTOS = BeanHelper.copyWithCollection(sysRoles, SysRoleDTO.class);
            sysCompanyUserDTO.setRoles(sysRoleDTOS);
        }

        return sysCompanyUserDTOList;
    }



    @Override
    public List<SysCompanyUserDTO> findAllCompanyUsers() {
        Long companyId = CurrentUserHolder.get().getCompanyId();
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId,companyId);
        wrapper.eq(SysCompanyUser::getEnable,1);
        List<SysCompanyUser> sysCompanyUserList = companyUserMapper.selectList(wrapper);
        return BeanHelper.copyWithCollection(sysCompanyUserList,SysCompanyUserDTO.class);
    }

    @Override
    public SysCompanyUserDTO queryCompanyUserById(Long companyUserId) {
        SysCompanyUser sysCompanyUser = companyUserMapper.selectById(companyUserId);
        return BeanHelper.copyProperties(sysCompanyUser,SysCompanyUserDTO.class);
    }

    @Override
    public PageResult<SysCompanyUserDTO> getDepartmentMembers(Integer page, Integer pageSize, Long departmentId, String keyword) {
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        //wrapper.eq(SysCompanyUser::getCompanyId,CurrentUserHolder.get().getCompanyId());
        if (departmentId != null){
            List<Long> idList = new ArrayList<>();
            idList.add(departmentId);
            getAllChildDeparmentId(idList,departmentId);
            wrapper.in(SysCompanyUser::getDepartmentId,idList);
        }
        if (!StringUtils.isEmpty(keyword)){

            wrapper.and(anotherWrapper ->{
                anotherWrapper.like(SysCompanyUser::getUserName,keyword)
                        .or()
                        .like(SysCompanyUser::getMobile,keyword)
                        .or()
                        .like(SysCompanyUser::getWorkNumber,keyword);
            });
        }
        IPage<SysCompanyUser> ipage = new Page<>(page,pageSize);
        ipage = companyUserMapper.selectPage(ipage,wrapper);
        List<SysCompanyUser> list = ipage.getRecords();
        if (!CollectionUtils.isEmpty(list)) {
            List<SysCompanyUserDTO> sysCompanyUserDTOList = list.stream().map(sysCompanyUser -> {
                SysCompanyUserDTO sysCompanyUserDTO = BeanHelper.copyProperties(sysCompanyUser, SysCompanyUserDTO.class);
                SysDepartmentDTO sysDepartmentDTO = new SysDepartmentDTO();
                sysDepartmentDTO.setId(sysCompanyUserDTO.getDepartmentId());
                sysDepartmentDTO.setName(sysCompanyUserDTO.getDepartmentName());
                sysCompanyUserDTO.setDepartment(sysDepartmentDTO);
                return sysCompanyUserDTO;
            }).collect(Collectors.toList());
            return new PageResult<>(ipage.getTotal(),ipage.getPages(),sysCompanyUserDTOList);
        }
        return new PageResult<>(ipage.getTotal(),ipage.getPages(),null);
    }

    private void getAllChildDeparmentId(List<Long> idList, Long departmentId) {
        LambdaQueryWrapper<SysDepartment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDepartment::getParentId,departmentId);
        wrapper.eq(SysDepartment::getCompanyId,CurrentUserHolder.get().getCompanyId());
        List<SysDepartment> sysDepartmentList = departmentMapper.selectList(wrapper);
        if (!CollectionUtils.isEmpty(sysDepartmentList)){
            for (SysDepartment sysDepartment : sysDepartmentList) {
                idList.add(sysDepartment.getId());
                getAllChildDeparmentId(idList,sysDepartment.getId());
            }
        }
    }

    @Override
    public void uploadExcel(MultipartFile file) throws Exception{
        //通过SpringMVC接收上传上来的文件，并对文件进行健壮性判断
        if (file == null){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        //通过EasyExcel来解析Excel文件，获取文件内容
        EasyExcel.read(file.getInputStream(),ExcelMember.class,new ExcelMemberListener(this)).sheet(0).doRead();

    }

    @Override
    public void handleParsedData(List<ExcelMember> list) {
        //需要判定手机号、邮箱是否已经被注册；判定员工工号是否被占用；
        for (ExcelMember excelMember : list) {
            checkMobileAndEmailExists(excelMember);
            //保存系统用户数据
            SysUser sysUser = saveUser(excelMember);
            //保存企业员工数据
            SysCompanyUser sysCompanyUser = saveCompanyUser(excelMember, sysUser);
            //维护企业员工关联的角色
            saveCompanyUserRole(excelMember,sysCompanyUser);
        }

    }

    @Override
    public SysCompanyUserDTO findCompanyUserByMobile(String mobile) {
        // 参数校验
        if(StringUtils.isEmpty(mobile)){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId,CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SysCompanyUser::getMobile,mobile);
        SysCompanyUser sysCompanyUser = companyUserMapper.selectOne(wrapper);
        return BeanHelper.copyProperties(sysCompanyUser,SysCompanyUserDTO.class);
    }

    private void saveCompanyUserRole(ExcelMember excelMember, SysCompanyUser sysCompanyUser) {
        LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysRole::getCompanyId,CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SysRole::getRoleDesc,excelMember.getRoleName());
        SysRole sysRole = roleMapper.selectOne(wrapper);
        if (sysRole != null){
            SysCompanyUserRole companyUserRole = new SysCompanyUserRole();
            companyUserRole.setCompanyUserId(sysCompanyUser.getId());
            companyUserRole.setRoleId(sysRole.getId());
            companyUserRole.setCompanyId(CurrentUserHolder.get().getCompanyId());

            companyUserRoleMapper.insert(companyUserRole);
        }

    }

    /**
     * 保存企业员工数据
     * @param excelMember
     * @param sysUser
     */
    private SysCompanyUser saveCompanyUser(ExcelMember excelMember, SysUser sysUser) {
        SysCompanyUser companyUser = new SysCompanyUser();
        companyUser.setUserId(sysUser.getId());
        companyUser.setCompanyId(CurrentUserHolder.get().getCompanyId());
        companyUser.setCompanyName(CurrentUserHolder.get().getCompanyName());
        companyUser.setPost(excelMember.getPosition());
        companyUser.setWorkNumber(excelMember.getWorkNumber());
        companyUser.setEmail(excelMember.getEmail());
        companyUser.setOfficeAddress(excelMember.getWorkAddr());
        companyUser.setTimeEntry(new Date());
        companyUser.setRemark("");
        companyUser.setEnable("可用".equals(excelMember.getEnable()) ? (short)1 : (short)0);
        companyUser.setCreateTime(new Date());
        companyUser.setUpdateTime(new Date());
        companyUser.setMobile(excelMember.getMobile());
        companyUser.setUserName(excelMember.getName());

        LambdaQueryWrapper<SysDepartment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDepartment::getName,excelMember.getDepartmentName());
        wrapper.eq(SysDepartment::getCompanyId,CurrentUserHolder.get().getCompanyId());
        SysDepartment sysDepartment = departmentMapper.selectOne(wrapper);
        if (sysDepartment != null) {
            companyUser.setDepartmentId(sysDepartment.getId());
            companyUser.setDepartmentName(sysDepartment.getName());
        }

        companyUserMapper.insert(companyUser);
        return companyUser;
    }

    /**
     * 存在员工表
     * @param excelMember
     */
    private SysUser saveUser(ExcelMember excelMember) {
        SysUser sysUser = new SysUser();
        sysUser.setUsername(excelMember.getName());
        sysUser.setPassword(new BCryptPasswordEncoder().encode("123456"));
        sysUser.setMobile(excelMember.getMobile());
        sysUser.setEmail(excelMember.getEmail());
        sysUser.setCreateTime(new Date());
        sysUser.setUpdateTime(new Date());
        sysUser.setStatus("可用".equals(excelMember.getEnable()) ? (short)1 : (short)0);
        sysUser.setLastLoginCompanyId(CurrentUserHolder.get().getCompanyId());
        userMapper.insert(sysUser);
        return sysUser;
    }

    /**
     * 判定手机号、邮箱是否已经被注册；判定员工工号是否被占用；
     * @param excelMember
     */
    private void checkMobileAndEmailExists(ExcelMember excelMember) {

        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId,CurrentUserHolder.get().getCompanyId());
        wrapper.and(w->{
            w.eq(SysCompanyUser::getMobile,excelMember.getMobile())
                    .or()
                    .eq(SysCompanyUser::getEmail,excelMember.getEmail())
                    .or()
                    .eq(SysCompanyUser::getWorkNumber,excelMember.getWorkNumber());
        });
        Integer count = companyUserMapper.selectCount(wrapper);
        if (count > 0){
            throw new NcException(ResponseEnum.USER_MOBILE_EMAIL_WORKNUMBER_EXISTS);
        }
    }
    @Override
    public Integer getAllUserByDepartmentIdList(List<Long> departmentIds) {
        List<Long> idList = new ArrayList<>();
        idList.addAll(departmentIds);
        for (Long departmentId : departmentIds) {
            getAllChildDeparmentId(idList,departmentId);
        }

        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(SysCompanyUser::getDepartmentId,idList);
        wrapper.eq(SysCompanyUser::getEnable,1);
        Integer count = companyUserMapper.selectCount(wrapper);
        return count;
    }

    @Override
    public SysCompanyUserDTO getAdminByCompanyId(Long companyId) {
        SysCompanyUser companyUser = companyUserMapper.getCurrentAdminByCompanyId(companyId);
        return BeanHelper.copyProperties(companyUser,SysCompanyUserDTO.class);
    }

    @Override
    public List<SysCompanyUserDTO> getAllUserByCompanyId(Long companyId) {

        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId,companyId);
        wrapper.eq(SysCompanyUser::getEnable,1);
        List<SysCompanyUser> companyUserList = companyUserMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(companyUserList)){
            throw new NcException(ResponseEnum.USER_NOT_FOUND);
        }
        return BeanHelper.copyWithCollection(companyUserList,SysCompanyUserDTO.class);
    }
}
